/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.cmd.component;

import cn.easyplatform.contexts.ListContext;
import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.dao.BizDao;
import cn.easyplatform.dao.Page;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.engine.runtime.datalist.DataListUtils;
import cn.easyplatform.entities.helper.EventLogic;
import cn.easyplatform.interceptor.AbstractCommand;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.GetListRequestMessage;
import cn.easyplatform.messages.response.GetListResponseMessage;
import cn.easyplatform.messages.response.SimpleResponseMessage;
import cn.easyplatform.messages.vos.GetListVo;
import cn.easyplatform.messages.vos.component.ListPageVo;
import cn.easyplatform.messages.vos.datalist.ListGetListVo;
import cn.easyplatform.support.scripting.CompliableScriptEngine;
import cn.easyplatform.support.scripting.ScriptEngineFactory;
import cn.easyplatform.support.sql.SqlParser;
import cn.easyplatform.type.Constants;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.type.FieldVo;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.util.MessageUtils;
import cn.easyplatform.util.RuntimeUtils;
import org.mozilla.javascript.NativeArray;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class GetListCmd extends AbstractCommand<GetListRequestMessage> {

    /**
     * @param req
     */
    public GetListCmd(GetListRequestMessage req) {
        super(req);
    }

    @Override
    public IResponseMessage<?> execute(CommandContext cc) {
        GetListVo gv = req.getBody();
        RecordContext rc = null;
        if (gv instanceof ListGetListVo) {
            ListGetListVo lgv = (ListGetListVo) req.getBody();
            ListContext lc = cc.getWorkflowContext().getList(lgv.getId());
            if (lc == null)
                return MessageUtils.dataListNotFound(lgv.getId());
            rc = lc.getRecord(lgv.getKeys());
            if (rc == null) {
                Record record = DataListUtils.getRecord(cc, lc, lgv.getKeys());
                rc = lc.createRecord(lgv.getKeys(), record);
                if (lc.getType().equals(Constants.CATALOG)) {
                    rc.setParameter("814", 'R');
                    rc.setParameter("815", Boolean.FALSE);
                    lc.appendRecord(rc);
                }
            }
        } else
            rc = cc.getWorkflowContext().getRecord();
        String query = gv.getQuery();
        if (query.startsWith("$")) {//变量
            Object val = rc.getValue(query.substring(1));
            if (val != null && !val.toString().trim().equals("")) {
                if (val instanceof List<?>) {
                    return new GetListResponseMessage((List<?>) val);
                } else if (val instanceof Object[][]) {
                    Object[][] objs = (Object[][]) val;
                    List<Object[]> tmp = new ArrayList<Object[]>(objs.length);
                    for (int i = 0; i < objs.length; i++)
                        tmp.add(objs[i]);
                    return new GetListResponseMessage(tmp);
                } else if (val instanceof Object[]) {
                    Object[] values = (Object[]) val;
                    if (values.length == 0 || !(values[0] instanceof NativeArray)) {
                        List<FieldVo[]> result = Collections.emptyList();
                        return new GetListResponseMessage(result);
                    }
                    List<Object[]> tmp = new ArrayList<Object[]>(values.length);
                    for (Object v : values) {
                        NativeArray na = (NativeArray) v;
                        Object[] rec = new Object[na.size()];
                        for (int i = 0; i < rec.length; i++)
                            rec[i] = na.get(i);
                        tmp.add(rec);
                    }
                    return new GetListResponseMessage(tmp);
                } else if (!(val instanceof String)) {
                    List<FieldVo[]> result = Collections.emptyList();
                    return new GetListResponseMessage(result);
                }
                query = val.toString();
            } else {
                List<FieldVo[]> result = Collections.emptyList();
                return new GetListResponseMessage(result);
            }
        }
        BizDao dao = cc.getBizDao(gv.getRid());
        SqlParser<FieldDo> sp = RuntimeUtils.createSqlParser(FieldDo.class);
        String sql = sp.parse(query, rc);
        List<FieldDo> params = sp.getParams();
        if (gv.getParameters() != null) {// like
            for (int i = 0; i < gv.getParameters().size(); i++) {
                Object value = gv.getParameters().get(i);
                params.add(new FieldDo(FieldType.cast(value), value));
            }
        }
        List<FieldDo[]> list = null;
        Page page = null;
        if (gv.getPageSize() > 0) {
            page = new Page(gv.getPageSize());
            page.setOrderBy(gv.getOrderBy());
            page.setPageNo(gv.getPageNo());
            page.setGetTotal(gv.isGetCount());
            list = dao.selectList(sql, params, page);
        } else {
            if (!Strings.isBlank(gv.getOrderBy()))
                sql += " order by " + gv.getOrderBy();
            list = dao.selectList(sql, params);
        }
        if (list.isEmpty()) {
            if (gv.isGetMetadataIfEmpty()) {
                int pos = query.toLowerCase().indexOf("where");
                if (pos > 0)
                    query = query.substring(0, pos);
                query += " WHERE 1=0";
                FieldDo[] fds = cc.getBizDao().getMetaData(query);
                int len = fds.length;
                FieldVo[] fvs = new FieldVo[len];
                for (int i = 0; i < len; i++)
                    fvs[i] = RuntimeUtils.castTo(fds[i]);
                return new SimpleResponseMessage(fvs);
            } else {
                List<FieldVo[]> result = Collections.emptyList();
                list = null;
                return new GetListResponseMessage(result);
            }
        } else {
            List<FieldVo[]> result = new ArrayList<FieldVo[]>(list.size());
            CompliableScriptEngine engine = null;
            if (!Strings.isBlank(gv.getFilter())) {
                EventLogic el = RuntimeUtils.castTo(cc, rc, gv.getFilter());
                if (el != null)
                    engine = ScriptEngineFactory.createCompilableEngine(cc,
                            el.getContent());
            }
            RecordContext target = null;
            try {
                for (FieldDo[] fds : list) {
                    if (engine != null) {
                        Record record = new Record();
                        for (int i = 0; i < fds.length; i++)
                            record.set(fds[i]);
                        if (target == null)
                            target = rc.clone();
                        target.setData(record);
                        Object obj = engine.eval(rc, target);
                        if (obj != null && obj instanceof Boolean
                                && (Boolean) obj)// 过滤掉了
                            continue;
                    }
                    int len = fds.length;
                    FieldVo[] fvs = new FieldVo[len];
                    for (int i = 0; i < len; i++)
                        fvs[i] = RuntimeUtils.castTo(fds[i]);
                    fds = null;
                    result.add(fvs);
                }
            } finally {
                if (engine != null) {
                    engine.destroy();
                    engine = null;
                }
                list = null;
            }
            if (page == null || !page.isGetTotal())
                return new GetListResponseMessage(result);
            else
                return new SimpleResponseMessage(new ListPageVo(
                        page.getTotalCount(), result));
        }
    }

}
